iT邦幫忙

2021 iThome 鐵人賽

DAY 25
2

前情提要

「艾草艾草,你在做什麼?」

艾草:「沒特別做什麼呀!」

「艾草艾草,我問你喔!」

艾草:「嗯嗯,問呀,但為什麼都要叫我名字兩次呀?」

「透過兩次的呼叫希望可以喚醒存在你心中的真善美,能使你成為更棒的存在!」

艾草:「??」

「上次在哪本魔法書看到的呀,好像某個術式要呼叫兩次什麼的,實驗一下!」

艾草:「啊,你說的應該是閉包吧?這個術式比較複雜,再陪你複習一次原理吧!」


閉包 Closure

以下引用至 MDN:

閉包(Closure)是函式以及該函式被宣告時所在的作用域環境(lexical environment)的組合。

這樣可能不理解,來看一段程式碼:

像這樣函式內 return 函式,且內層函式內並沒有 textContent 變數,需要透過範圍鍊找到外層的 textContent 變數來使用,就稱為閉包。

function outer(text) {
	let textContent = text; 
  return function inner(name) {
    console.log(`${textContent},${name}`); //"Hello,艾草"
  };
}

閉包的呼叫要使用兩個小括號,只使用一個小括號時,會印出整個內層函式,第二個小括號會呼叫被 return 的函式,底下分別為使用一個及兩個小括號呼叫的印出結果:

一個小括號:

outer('Hello');

印出結果:

https://ithelp.ithome.com.tw/upload/images/20211009/201390661zvTLE53sb.png


兩個小括號:

outer('Hello')('艾草');

印出結果:

https://ithelp.ithome.com.tw/upload/images/20211009/20139066VutJyxeW0o.png


接下來,閉包還可以這樣使用:

將變數賦予值為外層函式後,再透過變數呼叫內層函式,一樣可以成功印出。

function outer(text) {
	let textContent = text;
  return function inner(name) {
    console.log(`${textContent},${name}`); //"Hello,艾草"
  };
}
let sayHello = outer('Hello');
sayHello('艾草');

為什麼內層函式可以持續取到外層函式的變數呢?

首先,傳值、傳參考文章內有提到:每宣告一個變數,都會有相對應的記憶體空間存放變數

每個執行環境都會有對應的記憶體空間存放變數、函式,所以當我們執行到程式碼 let sayHello = outer('Hello') 時會跑去建立函式 outer 的執行環境,而執行到 let textContent = text 時,該執行環境內會產生記憶體空間來存放 textContent 變數與其值。

執行堆疊會如下圖:

https://ithelp.ithome.com.tw/upload/images/20211008/20139066le9fWNEW9y.png

接下來回到全域執行環境執行到 sayHello('艾草') 時,會進行以下幾個步驟:

  1. 函式 outer 會離開執行環境
  2. 全域執行環境的記憶體空間會放進 sayHello()sayHello() 會指向函式 inner
  3. 執行堆疊新增函式 inner 的執行環境,並於記憶體空間放置參數 name
  4. 函式 inner 會需要參照外部函式 outer 的變數 textContent

而執行環境為了參考到外部變數 textContent 會將外部變數包覆起來,而這就是閉包。

https://ithelp.ithome.com.tw/upload/images/20211008/20139066Q1Rl3WUqZf.png

JavaScript 會保留我們需要透過範圍鍊參照的外部變數,即使該變數所在執行環境已離開執行堆疊。


總結

  • 閉包呼叫使用兩個小括號,第二個小括號會呼叫要回傳的內層函式
  • 每個執行環境都會有對應的記憶體空間存放變數、函式
  • 執行環境從執行堆疊離開並不影響範圍鍊參照其記憶體空間

參考文獻

JavaScript 全攻略:克服 JS 的奇怪部分(Udemy)
JavaScript 核心篇(六角學院)
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Closures


上一篇
中階魔法 - Callback Function
下一篇
中階魔法 - 閉包 Closure (二)
系列文
JavaScript 魔法入門 - 從入門到中階觀念30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

我要留言

立即登入留言